// Press Shift twice to open the Search Everywhere dialog and type `show whitespaces`,
// then press Enter. You can now see whitespace characters in your code.
import javax.swing.*;
import java.awt.*;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.util.Random;

public class Game2048 extends JPanel {
    Game2048(){
        setFocusable(true);
        addKeyListener(new KeyAdapter() {
            @Override
            public void keyPressed(KeyEvent e) {
                super.keyPressed(e);
                switch (e.getKeyCode()){
                    case KeyEvent.VK_UP -> moveUp();
                    case KeyEvent.VK_LEFT -> moveLeft();
                    case KeyEvent.VK_RIGHT -> moveRight();
                    case KeyEvent.VK_DOWN -> moveDown();
                }
                repaint();
                spawnTile();
                checkGameState();

            }
        });
        spawnTile();
        spawnTile();
    }

    private static final int SIZE = 4;
    private int[][] grid = new int[SIZE][SIZE];
    private boolean gameWin=false;
    private boolean gameLose=false;

    private final Random random = new Random();
    private void moveLeft(){
        for(int row=0; row<SIZE; row++){
            int[] mergedRow = new int[SIZE];
            int colIndex = 0;//mergedRow的第几列
            for(int col=0; col<SIZE; col++){
                if(grid[row][col] != 0){
                    if(colIndex > 0 && mergedRow[colIndex-1] == grid[row][col]){
                        mergedRow[colIndex - 1] *= 2;
                    }else{
                        mergedRow[colIndex] = grid[row][col];
                        colIndex++;
                    }
                }
            }
            System.arraycopy(mergedRow,0,grid[row],0,SIZE);
        }
    }
    private  void moveDown(){
        rotateRight();
        moveLeft();
        rotateRight();
        rotateRight();
        rotateRight();
    }
    private void moveRight(){
        rotateRight();
        rotateRight();
        moveLeft();
        rotateRight();
        rotateRight();
    }
    private void moveUp(){
        rotateRight();
        rotateRight();
        rotateRight();
        moveLeft();
        rotateRight();

    }
    private void rotateRight(){
        int[][]newGrid = new int[SIZE][SIZE];
        for(int row=0; row<SIZE; row++){
            for(int col=0; col<SIZE; col++){
                newGrid[col][SIZE-row-1] = grid[row][col];
            }

        }
        grid = newGrid;
    }
    private void checkGameState(){
        for(int row=0; row<SIZE; row++){
            for(int col=0; col<SIZE; col++){
                if(grid[row][col] == 2048){
                    gameWin = true;
                }
            }
        }
        boolean continueFlag = false;
        if(!gameWin){
            for(int row=0; row<SIZE; row++) {
                for (int col = 0; col < SIZE; col++) {
                    if(grid[row][col] == 0){
                        continueFlag = true;

                        break;
                    }
                    if(col<SIZE-1 && grid[row][col] == grid[row][col+1]){

                        continueFlag = true;
                        break;
                    }
                    if(row<SIZE-1 && grid[row][col] == grid[row+1][col]){

                        continueFlag = true;
                        break;
                    }
                }
                if(continueFlag)
                    break;
            }
        }
        if(!continueFlag)
           gameLose = true;

    }
    private void drawTile(Graphics g, int value,int x,int y){
        int p =(int)  ((int)Math.log(value)/Math.log(2));
        g.setColor(value == 0 ? Color.pink : new Color(255 - p*20,240,200));
        g.fillRect(x,y,100,100);
        g.setColor(Color.BLACK);
        g.drawRect(x,y,100,100);
        if(value != 0){
            String text = String.valueOf(value);
            FontMetrics fm = g.getFontMetrics();
            int textX =x + (100 -fm.stringWidth(text))/2;
            int textY =y + (100 -fm.getHeight())/2 + fm.getAscent();
            g.drawString(text,textX,textY);
        }
    }
    private void spawnTile(){
        boolean full = true;
        for(int row = 0; row<SIZE; row++){
            for (int col = 0;col<SIZE; col++){
                if(grid[row][col] == 0){
                    full = false;
                    break;
                }
            }
        }
        if(full){
            return;
        }
        int x,y;
        do{
            x = random.nextInt(SIZE);
            y = random.nextInt(SIZE);
        }while(grid[x][y] != 0);
        grid[x][y] = random.nextInt(10) < 5 ? 2 : 4;
    }
    @Override
    protected void paintComponent(Graphics g){
        super.paintComponent(g);
        g.setColor(Color.pink);
        g.fillRect(0,0,getWidth(),getHeight());
        for(int i=0;i<SIZE;i++){
            for(int j=0;j<SIZE;j++){
                drawTile(g,grid[i][j],j*100,i*100);
            }
        }
        g.setColor(Color.BLACK);
        if(gameWin){
            g.drawString("You WIN",getWidth()/2,getHeight()/2);
        }else if(gameLose){
            g.drawString("You LOSE",getWidth()/2,getHeight()/2);
        }
    }
    public static void main(String[] args) {
        JFrame frame = new JFrame("2048 GAME");
        frame.setSize(420,460);
        Game2048 game2048 = new Game2048();
        frame.add(game2048);
        frame.setVisible(true);


    }
}